package com.sangeng.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sangeng.constant.SystemConstants;
import com.sangeng.constant.enums.AppHttpCodeEnum;
import com.sangeng.domain.core.ResponseResult;
import com.sangeng.domain.dto.MenuListDto;
import com.sangeng.domain.vo.*;
import com.sangeng.service.RoleMenuService;
import com.sangeng.utils.BeanUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import com.sangeng.domain.entity.Menu;
import com.sangeng.mapper.MenuMapper;
import com.sangeng.service.MenuService;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

/**
 * 菜单权限表(Menu)表服务实现类
 *
 * @author makejava
 * @since 2025-06-26 16:12:51
 */
@Service("menuService")
@RequiredArgsConstructor
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements MenuService {

    private final RoleMenuService roleMenuService;

    /**
     * 构建菜单树
     * @param menus
     * @return
     */
    @Override
    public List<RouterVo> buildMenus(List<Menu> menus) {
//        if (menus == null) return new ArrayList<>();
//        List<RouterVo> routerVos = new ArrayList<>();
//        for (Menu menu : menus) {
//            if(menu.getParentId().equals(0L)){
//                RouterVo routerVo = new RouterVo();
//                routerVo = BeanUtil.copyBean(menu, routerVo.getClass());
//                ArrayList<RouterVo> children = new ArrayList<>();
//                for(Menu menu1 : menus){
//                    if(menu1.getParentId().equals(menu.getId())){
//                        RouterVo routerVo1 = new RouterVo();
//                        routerVo1 = BeanUtil.copyBean(menu1, routerVo1.getClass());
//                        children.add(routerVo1);
//                    }
//                }
//                routerVo.setChildren(children);
//                routerVos.add(routerVo);
//            }
//        }
//        return routerVos;
        if(menus == null) return new ArrayList<>();
        List<RouterVo> routerVos = menus.stream()
                .filter(menu -> menu.getParentId().equals(0L))
                .map(menu -> BeanUtil.copyBean(menu, RouterVo.class))
                .toList();
        return routerVos.stream()
                .map(routerVo -> routerVo.setChildren(getMenusChildren(routerVo, menus)))
                .sorted(Comparator.comparingInt(RouterVo::getOrderNum))
                .toList();
    }

    @Override
    public ResponseResult listAllMenus(MenuListDto menuListDto) {
        LambdaQueryWrapper<Menu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.orderByAsc(Menu::getParentId, Menu::getOrderNum)
                .in(Menu::getMenuType, SystemConstants.MENU, SystemConstants.CHILD_MENU)
                .like(menuListDto.getStatus() != null, Menu::getStatus, menuListDto.getStatus())
                .like(menuListDto.getMenuName() != null, Menu::getMenuName, menuListDto.getMenuName());
        List<Menu> menus = list(queryWrapper);
        List<MenuListVo> result = BeanUtil.copyBeanList(menus, MenuListVo.class);
        return ResponseResult.okResult(result);
    }

    @Override
    public ResponseResult addMenu(Menu menu) {
        return save(menu) ? ResponseResult.okResult() : ResponseResult.errorResult(AppHttpCodeEnum.INSERT_ERROR);
    }

    @Override
    public ResponseResult getMenuById(Long id) {
        UpdateMenuVo result = BeanUtil.copyBean(getById(id), UpdateMenuVo.class);
        return ResponseResult.okResult(result);
    }

    @Override
    public ResponseResult removeMeunById(Long id) {
        List<Menu> menus = list(new LambdaQueryWrapper<Menu>().eq(Menu::getParentId, id));
        if(menus.size() != 0){
            return ResponseResult.errorResult(AppHttpCodeEnum.SYSTEM_ERROR.getCode(), SystemConstants.HAS_CHILDREN);
        }
        return removeById(id) ? ResponseResult.okResult() : ResponseResult.errorResult(AppHttpCodeEnum.DELETE_ERROR);
    }

    @Override
    public ResponseResult updateMenuById(Menu menu) {
        if(menu.getParentId().equals(menu.getId())){
            return ResponseResult.errorResult(AppHttpCodeEnum.SYSTEM_ERROR.getCode(), SystemConstants.PARENT_ID_ERROR(menu.getMenuName()));
        }
        return updateById(menu) ? ResponseResult.okResult() : ResponseResult.errorResult(AppHttpCodeEnum.UPDATE_ERROR);
    }

    @Override
    public ResponseResult treeselect() {
        List<Menu> menus = list();
        List<TreeMenuPerms> treeMenuPerms = TreeMenuPermsBuild(menus);
        return ResponseResult.okResult(treeMenuPerms);
    }

    @Override
    public ResponseResult roleMenuTreeselect(Long id) {
        // 获取菜单列表
        List<Long> menuIds = new ArrayList<>();
        if(id.toString().equals(SystemConstants.Admin_USER)){
            menuIds = list().stream().map(Menu::getId).toList();
        }
        else menuIds = roleMenuService.selectMenuIdsByRoleId(id);
        // 排除根节点
        List<Long> checkedKeys = menuIds.stream()
                .filter(menuId -> menuId != 0)
                .toList();

        // 获取树状菜单
        List<Menu> treeMenus = list();
        List<TreeMenuPerms> treeMenuPerms = TreeMenuPermsBuild(treeMenus);

        // 返回数据
        return ResponseResult.okResult(new UpdateRoleMenuVo(treeMenuPerms, checkedKeys));
    }

    private List<RouterVo> getMenusChildren(RouterVo routerVo, List<Menu> menus) {
        return menus.stream()
                .map(menu -> BeanUtil.copyBean(menu, RouterVo.class))
                .toList()
                .stream()
                .filter(m -> m.getParentId().equals(routerVo.getId()))
                .map(m -> m.setChildren(getMenusChildren(m, menus)))
                .sorted(Comparator.comparingInt(RouterVo::getOrderNum))
                .toList();
    }

    /**
     * 构建树形菜单
     * @param menus
     * @return
     */
    private List<TreeMenuPerms> TreeMenuPermsBuild(List<Menu> menus) {
        return menus.stream()
                .filter(menu -> menu.getParentId().equals(0L))
                .sorted(Comparator.comparing(Menu::getOrderNum))
                .map(menu -> {
                    TreeMenuPerms treeMenuPerms = new TreeMenuPerms();
                    treeMenuPerms.setId(menu.getId());
                    treeMenuPerms.setLabel(menu.getMenuName());
                    treeMenuPerms.setParentId(menu.getParentId());
                    treeMenuPerms.setChildren(TreeMenuPermsBuildChildren(treeMenuPerms.getId(), menus));
                    return treeMenuPerms;
                })
                .toList();
    }

    private List<TreeMenuPerms> TreeMenuPermsBuildChildren(Long id, List<Menu> menus) {
        return menus.stream()
                .filter(menu -> menu.getParentId().equals(id))
                .sorted(Comparator.comparing(Menu::getOrderNum))
                .map(menu -> {
                    TreeMenuPerms treeMenuPerms = new TreeMenuPerms();
                    treeMenuPerms.setId(menu.getId());
                    treeMenuPerms.setLabel(menu.getMenuName());
                    treeMenuPerms.setParentId(menu.getParentId());
                    treeMenuPerms.setChildren(TreeMenuPermsBuildChildren(treeMenuPerms.getId(), menus));
                    return treeMenuPerms;
                })
                .toList();
    }
}

